package com.lu.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lu.mapper.SysResourcesMapper;
import com.lu.mapper.SysRoleResourcesMapper;
import com.lu.mapper.SysUserRoleMapper;
import com.lu.model.entity.SysResources;
import com.lu.model.entity.SysRoleResources;
import com.lu.model.entity.SysUser;
import com.lu.model.entity.SysUserRole;
import com.lu.model.enums.YesOrNoEnum;
import com.lu.model.exception.LuBootAssert;
import com.lu.model.request.ResourcesQueryRequest;
import com.lu.service.SysResourcesService;
import com.lu.service.SysUserService;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 资源表 服务实现类
 * </p>
 *
 * @author wangqieyu
 * @since 2022-07-26
 */
@RequiredArgsConstructor
@Service
public class SysResourcesServiceImpl extends ServiceImpl<SysResourcesMapper, SysResources> implements SysResourcesService {

  private final SysRoleResourcesMapper roleResourcesMapper;
  private final SysUserRoleMapper userRoleMapper;
  private final SysUserService userService;

  @Override
  public Long addResources(SysResources resources) {
    LuBootAssert.isTrue(ObjectUtil.isAllNotEmpty(resources.getName()), "请输入资源名称");
    LuBootAssert.isTrue(ObjectUtil.isAllNotEmpty(resources.getUrl()), "请输入资源接口");
    LuBootAssert.isTrue(ObjectUtil.isEmpty(resources.getStatus())
        || Arrays.stream(YesOrNoEnum.values()).anyMatch(o -> o.getValue() == resources.getStatus()), "无效的状态参数");
    LuBootAssert.isTrue(ObjectUtil.isEmpty(resources.getType())
        || Arrays.stream(SysResources.Type.values()).anyMatch(o -> o.getType() == resources.getType()), "无效的资源类型");
    this.checkUrlUnique(null, resources.getUrl());
    SysUser loginUser = (SysUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
    resources.setId(null);
    resources.setCreateUserId(loginUser.getId());
    resources.setUpdateUserId(loginUser.getId());
    this.baseMapper.insert(resources);
    return resources.getId();
  }

  @Override
  public SysResources updateResources(SysResources resources) {
    LuBootAssert.isTrue(ObjectUtil.isEmpty(resources.getStatus())
        || Arrays.stream(YesOrNoEnum.values()).anyMatch(o -> o.getValue() == resources.getStatus()), "无效的状态参数");
    LuBootAssert.isTrue(ObjectUtil.isEmpty(resources.getType())
        || Arrays.stream(SysResources.Type.values()).anyMatch(o -> o.getType() == resources.getType()), "无效的资源类型");
    LuBootAssert.isTrue(ObjectUtil.isAllNotEmpty(resources.getId()), "无效的参数");
    this.checkUrlUnique(resources.getId(), resources.getUrl());
    SysUser loginUser = (SysUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
    resources.setUpdateUserId(loginUser.getId());
    resources.setUpdateTime(LocalDateTime.now());
    this.baseMapper.updateById(resources);
    if(resources.getStatus() != null){
      this.updateLoginUser(resources.getId());
    }
    return this.baseMapper.selectById(resources.getId());
  }

  @Override
  public Integer updateStatus(Long id, Integer status) {
    LuBootAssert.isTrue(Arrays.stream(YesOrNoEnum.values()).anyMatch(o -> o.getValue() == status), "无效的状态参数");
    SysUser loginUser = (SysUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
    SysResources updateResource = new SysResources();
    updateResource.setId(id);
    updateResource.setStatus(status);
    updateResource.setUpdateUserId(loginUser.getId());
    updateResource.setUpdateTime(LocalDateTime.now());
    int res = this.baseMapper.updateById(updateResource);
    this.updateLoginUser(id);
    return res;
  }

  @Transactional(rollbackFor = Exception.class)
  @Override
  public String deleteResources(Long id) {
    //删除资源
    int rs01 = this.baseMapper.deleteById(id);
    this.updateLoginUser(id);
    //删除角色资源关系
    QueryWrapper<SysRoleResources> resourcesQueryWrapper = new QueryWrapper<>();
    resourcesQueryWrapper.eq("resource_id", id);
    List<SysRoleResources> sysRoleResources = roleResourcesMapper.selectList(resourcesQueryWrapper);
    int rs02 = 0;
    if(ObjectUtil.isNotEmpty(sysRoleResources)){
      rs02 = roleResourcesMapper.deleteBatchIds(sysRoleResources.stream().map(SysRoleResources::getId).collect(Collectors.toList()));
    }
    this.updateLoginUser(sysRoleResources);
    return rs01 + "-" + rs02;
  }

  @Override
  public Page<SysResources> pageList(ResourcesQueryRequest request) {
    QueryWrapper<SysResources> resourcesQueryWrapper = new QueryWrapper<>();
    if(ObjectUtil.isNotEmpty(request.getStatus())){
      resourcesQueryWrapper.eq("status", request.getStatus());
    }
    if(ObjectUtil.isNotEmpty(request.getType())){
      resourcesQueryWrapper.eq("type", request.getType());
    }
    if(ObjectUtil.isNotEmpty(request.getName())){
      resourcesQueryWrapper.like("name", request.getName());
    }
    if(ObjectUtil.isNotEmpty(request.getUrl())){
      resourcesQueryWrapper.like("url", request.getUrl());
    }
    if(ObjectUtil.isNotEmpty(request.getIcon())){
      resourcesQueryWrapper.like("icon", request.getIcon());
    }
    resourcesQueryWrapper.orderByDesc("create_time");
    Page<SysResources> resourcesPage = this.baseMapper.selectPage(new Page<>(request.getPageIndex(), request.getPageSize()), resourcesQueryWrapper);
    return resourcesPage;
  }

  @Override
  public List<SysResources.TreeNodes> getListByPid(Long pid, Integer status) {
    QueryWrapper<SysResources> resourcesQueryWrapper = new QueryWrapper<>();
    if(ObjectUtil.isNotEmpty(status)){
      resourcesQueryWrapper.eq("status", "status");
    }
    if(ObjectUtil.isNotEmpty(pid)){
      resourcesQueryWrapper.eq("id", pid).or().eq("pid", pid);
    }
    resourcesQueryWrapper.orderByAsc("sort");
    List<SysResources> resources = this.baseMapper.selectList(resourcesQueryWrapper);
    return SysResources.treeNodes(resources, pid);
  }

  @Override
  public List<SysResources> sort(List<Long> ids) {
    if(ObjectUtil.isEmpty(ids)){
      return null;
    }
    for (int i = 0; i < ids.size(); i++) {
      SysResources resources = new SysResources();
      resources.setId(ids.get(i));
      resources.setSort(i);
      this.baseMapper.updateById(resources);
    }
    QueryWrapper<SysResources> resourcesQueryWrapper = new QueryWrapper<>();
    resourcesQueryWrapper.in("id", ids);
    return this.baseMapper.selectList(resourcesQueryWrapper);
  }

  private void checkUrlUnique(Long id, String url){
    if(ObjectUtil.isEmpty(url)){
      return;
    }
    QueryWrapper<SysResources> resourcesQueryWrapper = new QueryWrapper<>();
    resourcesQueryWrapper.eq("url", url);
    if(ObjectUtil.isNotEmpty(id)){
      resourcesQueryWrapper.ne("id", id);
    }
    Integer count = this.baseMapper.selectCount(resourcesQueryWrapper);
    LuBootAssert.isTrue(count == 0, "资源-接口不能重复");
  }

  public void updateLoginUser(Long resourceId){
    QueryWrapper<SysRoleResources> roleResourcesQueryWrapper = new QueryWrapper<>();
    roleResourcesQueryWrapper.eq("resource_id", resourceId);
    List<SysRoleResources> sysRoleResources = roleResourcesMapper.selectList(roleResourcesQueryWrapper);
    this.updateLoginUser(sysRoleResources);
  }

  public void updateLoginUser(List<SysRoleResources> sysRoleResources){
    if(ObjectUtil.isEmpty(sysRoleResources)){
      return;
    }
    QueryWrapper<SysUserRole> userRoleQueryWrapper = new QueryWrapper<>();
    userRoleQueryWrapper.in("role_id", sysRoleResources.stream().map(SysRoleResources::getRoleId).collect(Collectors.toList()));
    List<SysUserRole> userRoles = userRoleMapper.selectList(userRoleQueryWrapper);
    if(ObjectUtil.isEmpty(userRoles)){
      return;
    }
    for (SysUserRole userRole : userRoles) {
      userService.updateLoginUser(userRole.getUserId());
    }
  }
}
